﻿#region MyJScript - LGPL Copyright (c) 2008 Lionel Laské
//
// This file is part of MyJScript.
//
// MyJScript is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// MyJScript is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with MyJScript; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
//================================================================================
#endregion

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Microsoft.Scripting;
using Microsoft.Scripting.Runtime;
using Microsoft.Scripting.Utils;

[assembly: ExtensionType(typeof(string), typeof(MyJScript.Runtime.StringExtensions))]

namespace MyJScript.Runtime
{
    /// <summary>
    /// Delegate for a MyJScript function
    /// </summary>
    /// <param name="this">MyJScript this object</param>
    /// <param name="args">methods params</param>
    /// <returns></returns>
    public delegate Object MyJScriptCallTarget(Object @this, params Object[] args);

    /// <summary>
    /// Store all MyJScript built-in functions
    /// </summary>
    public class MJSLibrary
    {
        /// <summary>
        /// Test if initialized
        /// </summary>
        private static bool initialized = false;

        /// <summary>
        /// Initialize library. Put all built-in function in MyJScript context.
        /// </summary>
        internal static void Initialize()
        {
            // One time only
            if (initialized)
                return;
            initialized = true;

            // Register write function
            MJSObject mjscontext = MJSContext.GetContext();
            mjscontext.Set(
                "write",
                ReflectionUtils.CreateDelegate(
                    typeof(MJSLibrary).GetMethod("Write"),
                    typeof(MyJScriptCallTarget)
                )
            );

            // Register string type extensions
            RuntimeHelpers.RegisterAssembly(typeof(StringExtensions).Assembly);
        }

        /// <summary>
        /// Write object value to the console.
        /// </summary>
        /// <param name="value">value to print</param>
        /// <returns>null</returns>
        public static object Write(object @this, params object[] values)
        {
            foreach(object value in values)
                Console.Write(value != null ? value.ToString() : "<null>");
            Console.WriteLine();

            return null;
        }

        /// <summary>
        /// Try to compare two object supposing that one of both is a string.
        /// </summary>
        /// <param name="arg0">first object</param>
        /// <param name="arg1">second object</param>
        /// <returns>0 if arg0==arg1, 1 if arg0 &gt; arg1, -1 if arg0 &lt; arg1</returns>
        public static int CompareTo(object arg0, object arg1)
        {
            // Try to convert to int...
            int intarg0;
            int intarg1;
            if (arg0 is int)
            {
                intarg0 = (int)arg0;
                if (Int32.TryParse(arg1.ToString(), out intarg1))
                {
                    if (intarg0 > intarg1)
                        return 1;
                    else if (intarg0 < intarg1)
                        return -1;
                    else
                        return 0;
                }
            }
            else if (arg1 is int)
            {
                intarg1 = (int)arg1;
                if (Int32.TryParse(arg0.ToString(), out intarg0))
                {
                    if (intarg0 > intarg1)
                        return 1;
                    else if (intarg0 < intarg1)
                        return -1;
                    else
                        return 0;
                }
            }

            // ...else, convert both value to string
            return arg0.ToString().CompareTo(arg1.ToString());
        }
    }

    /// <summary>
    /// Class for MyJScript string primitives.
    /// </summary>
    public static class StringExtensions
    {
        /// <summary>
        /// Add blink tag around value
        /// </summary>
        /// <param name="this">this</param>
        /// <returns>value with blink tag around</returns>
        public static string blink(string @this)
        {
            // Append HTML tag
            StringBuilder res = new StringBuilder("<blink>");
            res.Append(@this);
            res.Append("</blink>");

            return res.ToString();
        }

        /// <summary>
        /// Add bold tag around value
        /// </summary>
        /// <param name="this">this</param>
        /// <returns>value with bold tag around</returns>
        public static string bold(string @this)
        {
            // Append HTML tag
            StringBuilder res = new StringBuilder("<bold>");
            res.Append(@this);
            res.Append("</bold>");

            return res.ToString();
        }

        /// <summary>
        /// Get a substring of the string.
        /// </summary>
        /// <param name="this">the string</param>
        /// <param name="index">index to start</param>
        /// <returns>the substring</returns>
        public static string substr(string @this, int index)
        {
            return @this.Substring(index);
        }

        /// <summary>
        /// Get a substring of the string.
        /// </summary>
        /// <param name="this">the string</param>
        /// <param name="index">index to start</param>
        /// <param name="length">length to get</param>
        /// <returns>the substring</returns>
        public static string substr(string @this, int index, int length)
        {
            return @this.Substring(index, length);
        }
    }
}
